﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using SunwellRenderer.Camera;
using Librarinth;

namespace SunwellRenderer.Rendering
{
	public struct DirLightData
	{
		public Vector3 Color;
		public Vector4[] SHLight;
	}
	public class CombineShader : ShaderEffect<DirLightData>
	{
		readonly int ColorRTIndex;
		readonly int NormalRTIndex;
		readonly int DepthRTIndex;
		readonly int BackRTIndex;
		readonly int ShadowMapIndex;
		public CombineShader() : base("HEXcontent/FX/POST/Combine")
		{
			Parent.AllGlobalTexture.GetIndex("GColor",out ColorRTIndex);
			Parent.AllGlobalTexture.GetIndex("GNormal",out NormalRTIndex);
			Parent.AllGlobalTexture.GetIndex("GDepth",out DepthRTIndex);
			Parent.AllGlobalTexture.GetIndex("GBack",out BackRTIndex);

			Parent.AllGlobalTexture.GetIndex("Shadow",out ShadowMapIndex);
		}

		protected override void OnDraw(GraphicsDevice device,int cameraIndex,BufferArray<int> dataIndexes)
		{
			var cameraWorld	= Parent.CameraModule.CameraWorld(cameraIndex);
			var invProjection	= Matrix.Invert(Parent.CameraModule.Projection(cameraIndex));
			Effect.Parameters["invProjection"].SetValue(invProjection);
			Effect.Parameters["View"].SetValue(Matrix.Invert(cameraWorld));

			foreach(var dataIndex in dataIndexes)
			{
				Effect.Parameters["colorMap"].SetValue(Parent.AllGlobalTexture.Datas[ColorRTIndex]);
				Effect.Parameters["normalMap"].SetValue(Parent.AllGlobalTexture.Datas[NormalRTIndex]);
				Effect.Parameters["depthMap"].SetValue(Parent.AllGlobalTexture.Datas[DepthRTIndex]);
				Effect.Parameters["lightMap"].SetValue(Parent.AllGlobalTexture.Datas[BackRTIndex]);

				var screenSize	= new Vector2(device.PresentationParameters.BackBufferWidth,device.PresentationParameters.BackBufferHeight);
				var halfPixel	= 0.5f * new Vector2(1 / screenSize.X,1 / screenSize.Y);

				Effect.Parameters["halfPixel"].SetValue(halfPixel);
				Effect.Parameters["ScreenSize"].SetValue(screenSize);

				var shadowMap	= Parent.AllGlobalTexture.Datas[ShadowMapIndex];
				float offsetX = 0.5f + (0.5f / shadowMap.Width);
				float offsetY = 0.5f + (0.5f / shadowMap.Height);

				var textureScaleBias	= new Matrix(0.5f,0.0f,0.0f,0.0f
											,0.0f,-0.5f,0.0f,0.0f
											,0.0f,0.0f,0.0f,0.0f
											,offsetX,offsetY,0.0f,1.0f);


				var light	= SunwellMain.Instance.Simulation.Datas[Datas[dataIndex].OBJIndex];
				var lightMatrix	= SunwellMain.Instance.SpatialModule.Datas[light.SpatialIndex].World;

				Effect.Parameters["lightMatrix"].SetValue(cameraWorld * lightMatrix);
				Effect.Parameters["textureScaleBias"].SetValue(textureScaleBias);

				Effect.Parameters["depthBias"].SetValue(0.001f);
				Effect.Parameters["shadowMap"].SetValue(shadowMap);
				Effect.Parameters["ShadowSize"].SetValue(shadowMap.Width);

				var distortCenter	= Vector3.Transform(new Vector3(0,0,-25),lightMatrix);
				Effect.Parameters["DistortCenter"].SetValue(Vector3.Normalize(distortCenter));


				int meshIndex	= Datas[dataIndex].MeshIndex;
				Effect.Parameters["EnvironmentSH"].SetValue(MeshDatas[meshIndex].SHLight);
				Effect.Parameters["Light1Color"].SetValue(MeshDatas[meshIndex].Color);
				Effect.Parameters["Light1Direction"].SetValue(-new Vector3(2,1,0));

				Effect.Begin();
				foreach(var pass in Effect.CurrentTechnique.Passes)
				{
					pass.Begin();

					QuadRenderComponent.Render(device);

					pass.End();
				}
				Effect.End();
			}
		}
	}

	public class CombineRenderer : Renderer
	{
		protected override IEnumerable<string> AllInitialShader
		{
			get { yield return typeof(CombineShader).Name; }
		}

		readonly int ShadowMapIndex;
		public CombineRenderer()
		{
			Parent.AllGlobalTexture.GetIndex("Shadow",out ShadowMapIndex);
		}

		SpriteBatch sprite;
		protected override void OnLoadContent()
		{
			sprite	= new SpriteBatch(SunwellMain.Instance.GraphicsDevice);
		}

		protected override void Begin(GraphicsDevice device)
		{
			device.Clear(Color.CornflowerBlue);
		}

		protected override void End(GraphicsDevice device)
		{
			sprite.Begin();
			sprite.Draw(Parent.AllGlobalTexture.Datas[ShadowMapIndex],new Rectangle(5,5,200,200),Color.White);
			sprite.End();
		}
	}
}